package intefly.tiwolf.mqttcamera.maiteCamera;

import static android.media.AudioRecord.STATE_UNINITIALIZED;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodecInfo;
import android.media.MediaRecorder;
import android.os.Process;

import com.ytf.dogbox.util.Log;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;



/** 对ACC音频进行编码
 * Created by jiangdongguo on 2017/5/6.
 * 通过设置音频的参数调整声音的间隔
 * 2022-10-26   问题：出现录音播放加快的现象；
 *              原因：是因为在3568这，getPcmBufferSize()获取到的返回值不是真是值，这应该和3568板子是64位或者是4核有关。这个原先的方法是在3288上面写的，3288是32位系统，并且只有一核。
 *              解决：在3288的getPcmBufferSize()获取的返回值为2048，所以将对应的getPcmBufferSize()返回值全部切换成2048。校验看下
 *
 *     java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord.还是有可能出现这个问题，不知道是这板子的特性还是其他导致的mAudioRecord没释放完，然后再次调用mAudioRecord.startRecording();这个的时候出现了问题
 */

public class AACproduct extends Thread {
    private static final String TAG = "AACproduct";
    private static final String MIME_TYPE = "audio/mp4a-latm";
    private static final int TIMES_OUT = 10000;
    private static final int ACC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
    private static final int BUFFER_SIZE = 1600;
//    private static final int AUDIO_BUFFER_SIZE = 1024;
    private static final int AUDIO_BUFFER_SIZE = 1600;
    /**默认比特率*/
    public static final int DEFAULT_BIT_RATE = 48000;
    /**默认采样率*/
    public static final int DEFAULT_SAMPLE_RATE = 8000;

    /**通道数为1*/
    public static final int CHANNEL_COUNT_MONO = 1;
    /**通道数为2*/
    public static final int CHANNEL_COUNT_STEREO = 2;
    /**单声道*/
    public static final int CHANNEL_IN_MONO = AudioFormat.CHANNEL_IN_MONO;
    /**立体声*/
    public static final int CHANNEL_IN_STEREO = AudioFormat.CHANNEL_IN_STEREO;
    /**16位采样精度*/
    public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT;
    /**8位采样精度*/
    public static final int ENCODING_PCM_8BIT = AudioFormat.ENCODING_PCM_8BIT;
    /**音频源为MIC*/
    public static final int SOURCE_MIC = MediaRecorder.AudioSource.MIC;
    /**音频源为Default*/
    public static final int SOURCE_DEFAULT = MediaRecorder.AudioSource.DEFAULT;
    /**音频源为蓝牙*/
    public static final int SOURCE_COMMUNICATION = MediaRecorder.AudioSource.VOICE_COMMUNICATION;

    private AudioRecord mAudioRecord;
    // 编码器
    private boolean isExit = false;

    private int errorAudioNum=0;
    private int lastNumber=0;

    public AACproduct(IshowPcm ishowPcm){
        Log.e(TAG, "AACproduct: 摄像头音频--从外面进来了一次11111111111111111111");
        isExit=false;
        this.ishowPcm=ishowPcm;
        lookAudio();
    }

    public void lookAudio(){
        //TODO 2021-05-08 这个方法可以将音频重启起来（事后补偿法）
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isExit){
//                    Log.e(TAG, "restartAudio 音频-----------我是一直在奔跑"+Thread.currentThread().getName());
                    if (errorAudioNum!=0 && errorAudioNum==lastNumber){
                        Log.e(TAG, "restartAudio run: 音频--出错了" );
                        isExit=true;
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
//                        Log.e(TAG, "restartAudio audio摄像头音频声音 stopAudioRecord: 全部关闭，准备重新打开一个1111" );
                        if (ishowPcm!=null){
                            ishowPcm.errorAudio();
                        }
                    }else {
                        lastNumber=errorAudioNum;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

	@Override
	public void run() {
        Log.e(TAG, "run6666: 录制="+currentThread().getName() );
        if (mAudioRecord==null || mAudioRecord.getState()==STATE_UNINITIALIZED){

                try {
                    startAudioRecord();
                }catch (Exception e){
                    e.printStackTrace();
                    Log.e(TAG, "run: 录制出现错误" );
                    isExit=true;
                }


                Log.e(TAG, "ai audio 摄像头音频--  开始录制和编译"+mAudioRecord.getState() );

//			File file=new File(FileSortUtil.appPath+"log/intefly.pcm");
//            try {
//                file.createNewFile();
//                fos = new FileOutputStream(FileSortUtil.appPath+"log/intefly.pcm");
//            } catch (IOException e) {
//                e.printStackTrace();
//            }



            byte[] audioBuf = new byte[2048];
            while (!isExit) {
                //补救方法，使用自巡数据监测音频是否已经挂掉，如果挂掉则重启启动。  根本处理：还需要了解问题根源
                long start=System.currentTimeMillis();

                errorAudioNum++;
                if (errorAudioNum>200){
                    errorAudioNum=1;
                }
//            Log.e(TAG, "run: 摄像头音频----进去执行一次声音拾取+++++++++++++++++++++++++++++++"+errorAudioNum+";;;"+isExit);
                if (mAudioRecord != null) {
                    try {
                        int readBytes = mAudioRecord.read(audioBuf, 0,2048);
                        if (readBytes>0 && AudioRecord.ERROR_INVALID_OPERATION!=readBytes){
//                        Log.i(TAG,"摄像头录音---->数据大小,读取成功："+readBytes);
                            //正常情况下，每次都会到这里拾取声音。在这里将数据变0
                            ishowPcm.showpcm(audioBuf,readBytes);
                        }else {
                            Log.e(TAG, "startplay audio 摄像头音频3：没有读取到数据" );
                            isExit=true;//如果出现获取不到音频数据的情况，说明audiorecord已经有问题.则跳出
                        }

                    }catch (IllegalStateException e){
                        Log.e(TAG, "audio 摄像头音频1: "+e.getMessage() );
                        isExit=true;
                    }catch (NullPointerException e) {
                        // 捕获因中断线程并停止混合MediaCodec为NULL异常
                        Log.e(TAG, "audio 摄像头音频2: "+e.getMessage() );
                        e.printStackTrace();
                        isExit=true;
                    }catch (Exception e){
                        Log.e(TAG, "run: audio 摄像头音频3："+e.getMessage() );
                        isExit=true;
                    }

//                Log.e(TAG, "audio 摄像头音频000: "+readBytes );
//				if (readBytes > 0) {
//					try {
////                        Log.i(TAG,"摄像头录音---->数据大小,读取成功："+readBytes);
//                        Log.e(TAG, "audio 成功摄像头音频000: "+readBytes );
//                        ishowPcm.showpcm(audioBuf,readBytes);
//					} catch (IllegalStateException e) {
//						// 捕获因中断线程并停止混合dequeueOutputBuffer报的状态异常
//                        Log.e(TAG, "audio 摄像头音频1: "+e.getMessage() );
////                        isExit=true;
//						e.printStackTrace();
//					} catch (NullPointerException e) {
//						// 捕获因中断线程并停止混合MediaCodec为NULL异常
//                        Log.e(TAG, "audio 摄像头音频2: "+e.getMessage() );
//						e.printStackTrace();
////                        isExit=true;
//					}
////					catch (IOException e) {

////                    }
//                }else {
//                    Log.e(TAG, "startplay audio 摄像头音频3：没有读取到数据" );
//                    isExit=true;//如果出现获取不到音频数据的情况，说明audiorecord已经有问题.则跳出
//                }
                }else{
                    Log.e(TAG, "run: 摄像头音频出现mAudioRecord为空的问题");
                }
                long end=System.currentTimeMillis();
//            Log.e(TAG, "读取一次音频声音的时间为--" +(end-start));
            }
            Log.e(TAG, "audio run: 摄像头音频初始化之音频aac关闭" );

            stopAudioRecord();
        }


    }


    int min_buffer_size=0;
    int buffer_size=0;
    private void startAudioRecord(){
        // 计算AudioRecord所需输入缓存空间大小
//        EncoderParams mParams = mParamsRef.get();
//        int bufferSizeInBytes = AudioRecord.getMinBufferSize(mParams.getAudioSampleRate(),mParams.getAudioChannelConfig(),
//                mParams.getAudioFormat());
//        if(bufferSizeInBytes < 1600){
//            bufferSizeInBytes = 1600;
//        }
//        Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
//        mAudioRecord = new AudioRecord(mParams.getAudioSouce(),mParams.getAudioSampleRate(),
//                mParams.getAudioChannelConfig(),mParams.getAudioFormat(),bufferSizeInBytes);
//        min_buffer_size = AudioRecord.getMinBufferSize(
//                48000, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT);
        /* TODO 填错一个参数会导致大问题，程序极其容易anr，，应该是CHANNEL_IN_STEREO，下面注释这个是错误的
        min_buffer_size = AudioRecord.getMinBufferSize(
                48000, CHANNEL_COUNT_STEREO, ENCODING_PCM_16BIT);*/
//        buffer_size = AUDIO_BUFFER_SIZE * 20;
//        if (buffer_size < min_buffer_size)
//            buffer_size = ((min_buffer_size / AUDIO_BUFFER_SIZE) + 1) * AUDIO_BUFFER_SIZE * 2;



        Log.e(TAG, "ai startAudioRecord: 摄像头音频 得到的buffer_size="+getPcmBufferSize() );
        Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
//        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        if (mAudioRecord==null){
            mAudioRecord = new AudioRecord(SOURCE_MIC,DEFAULT_BIT_RATE ,
                    CHANNEL_IN_STEREO,ENCODING_PCM_16BIT,2048);
        }


        // 开始录音
        mAudioRecord.startRecording();
    }

    //TODO 好像换到这个之后音频问题才好一些，其他的都出现了奇怪的问题。大部分都是生产裸音频一段时间之后就停下来了。
    // 2022-10-26 处理：正常情况下，在3288主板上这里getPcmBufferSize()方法获取到的返回值为2048byte；但是在3568主板上，这里获取到的参数为8960byte.
    // 但实际上有录音的数据是为2048byte。所以如果按照3288的代码原搬过来的话，2048byte之后都是无效数据，这里多了8960-2048=6812byte。
    // 这些无效数据通过showpcm往外发，当对当前录制的录音进行播放的时候，就会出现语速加快的情况。
    // 像这里，语速加快将近4倍。而且只有1/4的是有声音的，其他都是无效的沙沙响。
    // 当前的解决方法：取一帧pcm数据的时候，只需要取0-2048的数据，其他的不管。即int readBytes = mAudioRecord.read(audioBuf, 0,2048);这样即可使录音文件正常，至于其他问题还在检查中
    private int getPcmBufferSize() {
        int pcmBufSize = AudioRecord.getMinBufferSize(DEFAULT_BIT_RATE, CHANNEL_IN_STEREO,
                ENCODING_PCM_16BIT) ;
        return pcmBufSize;
    }

    public void stopRecordFlag(){
        Log.e(TAG, "stopRecordFlag: 摄像头音频关掉录音，问题出现===============" );
	    isExit=true;
    }

    Lock lock=new ReentrantLock();
    public void stopAudioRecord(){
        lock.lock();
        try {
            Log.e(TAG, "stopAudioRecord: 摄像头音频 pcm出现问题000" );
            if (mAudioRecord!=null){
                mAudioRecord.stop();
                Log.e(TAG, "stopAudioRecord: 摄像头音频 pcm出现问题111=stop" );
                mAudioRecord.release();
                Log.e(TAG, "stopAudioRecord: 摄像头音频 pcm出现问题222=release" );
            }
            mAudioRecord = null;
        }catch (IllegalStateException e){
            Log.e(TAG, "stopAudioRecord: 摄像头音频 pcm出现问题"+e.getMessage() );
            //todo 如果当前java状态和jni里面状态不一样
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        //重新生成一个
//        Log.e(TAG, "摄像头音频 audio声音 stopAudioRecord: 全部关闭，准备重新打开一个" );
//        isExit=true;
        //不能在子线程里面new handler，否则报错
//        new Handler().postDelayed(new Runnable() {
//            @Override
//            public void run() {
//                if (ishowPcm!=null){
//                    ishowPcm.errorAudio();
//                }
//            }
//        },200);
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    Thread.sleep(200);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                Log.e(TAG, "audio摄像头音频声音 stopAudioRecord: 全部关闭，准备重新打开一个1111" );
//                if (ishowPcm!=null){
//                    ishowPcm.errorAudio();
//                }
//            }
//        }).start();


    }


    IshowPcm ishowPcm;
    public void setPcm(IshowPcm ishowPcm){
        this.ishowPcm=ishowPcm;
    }
    public interface IshowPcm{
        //        void show(Bitmap bitmap);
        void showpcm(byte[] pcm, int length);

        void errorAudio();
    }
}
